using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using NUtil.lists;

namespace NUtil {
    public class ListUtils {
        public static IList<T> Slice<ST, T>(IList<ST> source) {
            FieldInfo[] fields = typeof(ST).GetFields(BindingFlags.Instance | BindingFlags.NonPublic);
            if (fields.Length > 0) {
                return Slice<ST, T>(source, fields[0]);
            }
            throw new ApplicationException("No fields found in the source class");
        }

        public static IList<T> Slice<ST, T>(IList<ST> source, String sliceFieldName) {
            FieldInfo field = typeof(ST).GetField(sliceFieldName, BindingFlags.Instance | BindingFlags.NonPublic);
            if (field != null) {
                return Slice<ST, T>(source, field);
            }
            throw new ApplicationException(string.Format("No field with the name '{0}' found in class {1}", sliceFieldName, typeof(ST).Name));
        }

        public static IList<T> Slice<ST, T>(IList<ST> source, int fieldIndex) {
            FieldInfo[] fields = typeof(ST).GetFields(BindingFlags.Instance | BindingFlags.NonPublic);
            if ((fieldIndex >= 0) && (fields.Length >= fieldIndex + 1))
            {
                return Slice<ST, T>(source, fields[fieldIndex]);
            }
            throw new ApplicationException(string.Format("No fields on index {0} found in class {1}", fieldIndex, typeof(ST).Name));
        }

        private static IList<T> Slice<ST, T>(IList<ST> source, FieldInfo fieldToSlice) {
            IList<T> list = new List<T>();
            if (source.Count > 0) {
                Assert.IsTrue(typeof(T).Equals(fieldToSlice.FieldType));
                foreach (ST sourceItem in source) {
                    list.Add((T)fieldToSlice.GetValue(sourceItem));
                }
            }
            return list;
        }

        public static IList<T> NewList<T>(params T[] elements) {
            List<T> result = new List<T>();
            result.AddRange(elements);
            return result;
        }

        public static IList<T> ToImmutableList<T>(IList<T> source) {
            return new ImmutableList<T>(source);
        }

        public static IList<T> ToTypedList<T>(IList list) {
            if (list == null) {
                return null;
            }
            List<T> typedList = new List<T>();
            foreach (T t in list) {
                typedList.Add(t);
            }
            return typedList;
        }

        public static string Join<T>(IList<T> list) {
            return Join<T>(list, ",");
        }


        public static string Join<T>(string delimiter, params T[] objects) {
            return Join((IList) NewList(objects), delimiter); //TODO: performance optm - Anand
        }

        public static string Join<T>(IList<T> list, string separator) {
            if (list == null) {
                return string.Empty;
            }
            StringBuilder result = new StringBuilder();
            foreach (T item in list) {
                result.Append(item == null ? string.Empty : ((Object) item).ToString());
                if (list.IndexOf(item) != list.Count - 1) {
                    result.Append(separator);
                }
            }
            return result.ToString();
        }

        public static string Join(IList list) {
            return Join(list, ",");
        }

        public static string Join(IList list, string separator) {
            return Join(ToTypedList<Object>(list), separator);
        }

        public static bool ListEqual(IList list1, IList list2) {
            return new ListEquals().ListEqual(list1, list2, false);
        }

        public static bool ListEqual(IList list1, IList list2, bool orderMatters) {
            return new ListEquals().ListEqual(list1, list2, orderMatters);
        }
    }
}